/*-
 * Copyright (c) 2009-2010 David Forsythe.
 * See LICENSE file for license details.
 */

#ifndef __LIBPKG_PROPERTY_H__
#define __LIBPKG_PROPERTY_H__

#include <sys/tree.h>
#include <sys/types.h>
#include <sys/queue.h>

/* 
 * struct pkg_property - A generic property type for package property lists.
 * Data is copied in and referenced out.  Current support integer properties,
 * time properties, and string properties.  Properties can exist alone, or exist
 * as a listable type, which can be iterated over.
 */
typedef enum {
        PLBOOL,         /* 0/1 value. */
        PLDATA,         /* Blob. */
        PLDATE,         /* time_t value. */
        PLDICT,         /* Property dictionary. */
        PLLIST,         /* A list of property objects. */
        PLNONE,         /* Nonetype for newly initialized property objects. */
        PLNUMBER,       /* A number value. */
        PLSTRING        /* A c string value. */
} property_type_t;

/*
 * XXX: Using a splay tree for proof of concept, use a hash table for complete
 * implementation.
 * 
 * Maybe drop the tailq for a normal linked list, not from queue(3)...
 */
struct pkg_property {
        struct {
                property_type_t property_type;
                const char *property_type_name;
                const char *property_name;
        } info;
        union {
                int boolean;
                struct {
                        void *data;
                        size_t size;
                } data;
                int64_t integer;
                time_t date;
                char *string;
                /* XXX struct pkg_property *dict; XXX */
                SPLAY_HEAD(property_dict, pkg_property) dict_head;
                TAILQ_HEAD(property_list, pkg_property) list_head;
        } root;
        int root_set:1;
        union {
                SPLAY_ENTRY(pkg_property) dict_entry;
                TAILQ_ENTRY(pkg_property) list_entry;
        } entry;
        /* For lists. */
        int sort:1;
        int sorted:1;
        struct pkg_property *cursor;
};

/* This needs to be hidden. */
struct pkg_property *
pkg_property_create(void);

void
pkg_property_release(struct pkg_property *);

/* 
 * Create and initialize a new Plist, which is a single dictionary node.
 * Identify the Plist with plname for debugging. 
 */
#define pkg_property_plist_create(plname) \
        pkg_property_dict_create(NULL, plname);

const char *pkg_property_get_name(struct pkg_property *);

property_type_t pkg_property_get_type(struct pkg_property *);

const char *pkg_property_get_type_name(struct pkg_property *);

/* XXX: NOT IMPLENTED */
struct pkg_property *pkg_property_get_next_property(struct pkg_property *, 
        struct pkg_property *);

struct pkg_property *pkg_property_dict_create(struct pkg_property *, 
        const char *);

struct pkg_property *pkg_property_dict_get_property(struct pkg_property *, 
        const char *);

struct pkg_property *pkg_property_dict_get_next_property(struct pkg_property *, 
        struct pkg_property *);

struct pkg_property *pkg_property_list_create(struct pkg_property *, 
        const char *);

struct pkg_property *pkg_property_list_get_next_property(struct pkg_property *, 
        struct pkg_property *);

struct pkg_property *pkg_property_list_sequence_get_next_property(
        struct pkg_property *);

void pkg_property_list_sequence_rewind(struct pkg_property *);

struct pkg_property *pkg_property_list_sort(struct pkg_property *, 
        int (*) (struct pkg_property *, struct pkg_property *));

void pkg_property_list_remove_property(struct pkg_property *,
        struct pkg_property *);

struct pkg_property *pkg_property_boolean_create(struct pkg_property *, 
        const char *);

void pkg_property_boolean_set_boolean(struct pkg_property *, int);

#define pkg_property_boolean_set_true(p) \
pkg_property_boolean_set_boolean(p, 1)

#define pkg_property_boolean_set_false(p) \
pkg_property_boolean_set_boolean(p, 0)

int pkg_property_boolean_get_boolean(struct pkg_property *);

struct pkg_property *pkg_property_string_create(struct pkg_property *, 
        const char *);

const char *pkg_property_string_set_string(struct pkg_property *, 
        const char *);

const char *pkg_property_string_get_string(struct pkg_property *);

struct pkg_property *pkg_property_number_create(struct pkg_property *, 
        const char *);

void pkg_property_number_set_number(struct pkg_property *, int64_t);

int64_t pkg_property_number_get_number(struct pkg_property *);

struct pkg_property *pkg_property_date_create(struct pkg_property *, 
        const char *);

void pkg_property_date_set_date(struct pkg_property *, time_t);

time_t pkg_property_date_get_date(struct pkg_property *);

struct pkg_property *pkg_property_data_create(struct pkg_property *,
        const char *);

const void *pkg_property_data_set_data(struct pkg_property *, const void *, 
        size_t);

const void *pkg_property_data_read_data(struct pkg_property *, int, size_t);

ssize_t pkg_property_data_get_data(struct pkg_property *, const void **);

#endif
